﻿namespace Beetle
{
    using System;
    using System.Collections.Generic;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Text;
    using System.Threading;

    public class TcpServer : IDisposable
    {
        private EventTcpServerError _field_a;
        private bool _field_b;
        private object _field_c = new object();
        private Class_r _field_d;
        private int _field_e = 0xff;
        private ChannelCreatingArgs _field_f = new ChannelCreatingArgs();
        internal static string _field_g = "73HWrM6iCrk=";
        private System.Net.Sockets.Socket _field_h;
        private Class_x _field_i;
        private Queue<Class_r> _field_j = new Queue<Class_r>(0x400);
        private Dictionary<Type, IIPFiler> _field_k = new Dictionary<Type, IIPFiler>();
        private DetectTimeoutHandler _field_l;
        private EventChannglCreating _field_m;
        private bool _field_n;
        internal IList<TcpChannel> _field_o;
        private IPEndPoint _field_p;
        private EventChannelConnected _field_q;
        private EventChannelDisposed _field_r;
        private bool _field_s;
        private object _field_t = new object();
        [CompilerGenerated]
        private Encoding _field_u;
        [CompilerGenerated]
        private bool _field_v;
        public bool EnabledVariant;
        public static ObjectPool<SocketAsyncEventArgs> SocketAsyncEventArgsPools = new ObjectPool<SocketAsyncEventArgs>(0x400);

        public event EventChannelConnected ChannelConnected
        {
            add
            {
                EventChannelConnected connected2;
                EventChannelConnected connected = this._field_q;
                do
                {
                    connected2 = connected;
                    EventChannelConnected connected3 = (EventChannelConnected) Delegate.Combine(connected2, value);
                    connected = Interlocked.CompareExchange<EventChannelConnected>(ref this._field_q, connected3, connected2);
                }
                while (connected != connected2);
            }
            remove
            {
                EventChannelConnected connected2;
                EventChannelConnected connected = this._field_q;
                do
                {
                    connected2 = connected;
                    EventChannelConnected connected3 = (EventChannelConnected) Delegate.Remove(connected2, value);
                    connected = Interlocked.CompareExchange<EventChannelConnected>(ref this._field_q, connected3, connected2);
                }
                while (connected != connected2);
            }
        }

        public event EventChannglCreating ChannelCreating
        {
            add
            {
                EventChannglCreating creating2;
                EventChannglCreating creating = this._field_m;
                do
                {
                    creating2 = creating;
                    EventChannglCreating creating3 = (EventChannglCreating) Delegate.Combine(creating2, value);
                    creating = Interlocked.CompareExchange<EventChannglCreating>(ref this._field_m, creating3, creating2);
                }
                while (creating != creating2);
            }
            remove
            {
                EventChannglCreating creating2;
                EventChannglCreating creating = this._field_m;
                do
                {
                    creating2 = creating;
                    EventChannglCreating creating3 = (EventChannglCreating) Delegate.Remove(creating2, value);
                    creating = Interlocked.CompareExchange<EventChannglCreating>(ref this._field_m, creating3, creating2);
                }
                while (creating != creating2);
            }
        }

        public event EventChannelDisposed ChannelDisposed
        {
            add
            {
                EventChannelDisposed disposed2;
                EventChannelDisposed disposed = this._field_r;
                do
                {
                    disposed2 = disposed;
                    EventChannelDisposed disposed3 = (EventChannelDisposed) Delegate.Combine(disposed2, value);
                    disposed = Interlocked.CompareExchange<EventChannelDisposed>(ref this._field_r, disposed3, disposed2);
                }
                while (disposed != disposed2);
            }
            remove
            {
                EventChannelDisposed disposed2;
                EventChannelDisposed disposed = this._field_r;
                do
                {
                    disposed2 = disposed;
                    EventChannelDisposed disposed3 = (EventChannelDisposed) Delegate.Remove(disposed2, value);
                    disposed = Interlocked.CompareExchange<EventChannelDisposed>(ref this._field_r, disposed3, disposed2);
                }
                while (disposed != disposed2);
            }
        }

        public event EventTcpServerError Error
        {
            add
            {
                EventTcpServerError error2;
                EventTcpServerError error = this._field_a;
                do
                {
                    error2 = error;
                    EventTcpServerError error3 = (EventTcpServerError) Delegate.Combine(error2, value);
                    error = Interlocked.CompareExchange<EventTcpServerError>(ref this._field_a, error3, error2);
                }
                while (error != error2);
            }
            remove
            {
                EventTcpServerError error2;
                EventTcpServerError error = this._field_a;
                do
                {
                    error2 = error;
                    EventTcpServerError error3 = (EventTcpServerError) Delegate.Remove(error2, value);
                    error = Interlocked.CompareExchange<EventTcpServerError>(ref this._field_a, error3, error2);
                }
                while (error != error2);
            }
        }

        public TcpServer()
        {
            this.Coding = Encoding.UTF8;
            this._field_o = new List<TcpChannel>(TcpUtils.Connections);
            this.EnabledChannelSendCompeletedEvent = false;
            this._field_l = new DetectTimeoutHandler();
            this._field_l.Server=(this);
            this._field_i = Class_x.g();
        }

        private bool a()
        {
            return (this._field_o.Count < Class_ag._field_a);
        }

        private void a(TcpChannel A_0)
        {
            lock (this._field_c)
            {
                this.Clients.Add(A_0);
                A_0._field_ae = A_0._field_d > ((int) A_0["_data"]);
            }
        }

        private void a(Class_r A_0)
        {
            TcpChannel channel = null;
            bool flag = true;
            if (this._field_k.Count > 0)
            {
                foreach (KeyValuePair<Type, IIPFiler> pair in this._field_k)
                {
                    flag = pair.Value.Execute((IPEndPoint) A_0._field_b.RemoteEndPoint);
                    if (!flag)
                    {
                        break;
                    }
                }
            }
            if (flag)
            {
                channel = new TcpChannel(A_0._field_b) {
                    EnabledVariant = this.EnabledVariant
                };
                this.c(channel);
                channel.EnabledSendCompeletedEvent = this.EnabledChannelSendCompeletedEvent;
                this.OnConnected(channel);
            }
            else
            {
                A_0._field_b.Shutdown(SocketShutdown.Both);
                A_0._field_b.Close();
            }
        }

        private void a(Exception A_0)
        {
            TcpServerErrorArgs e = new TcpServerErrorArgs {
                Error = A_0
            };
            try
            {
                this.OnError(e);
            }
            catch
            {
            }
        }

        private void a(System.Net.Sockets.Socket A_0)
        {
            ReleaseSocket(A_0);
        }

        private void a(SocketAsyncEventArgs A_0)
        {
            try
            {
                if ((A_0.SocketError == SocketError.Success) && !this._field_s)
                {
                    Class_r _r = new Class_r {
                        _field_b = A_0.AcceptSocket
                    };
                    this.b(_r);
                }
                else
                {
                    ReleaseSocket(A_0.AcceptSocket);
                }
                A_0.AcceptSocket = null;
            }
            catch (Exception exception)
            {
                this.a(exception);
            }
            finally
            {
                this._field_b = false;
                A_0.Completed -= new EventHandler<SocketAsyncEventArgs>(this.b);
                SocketAsyncEventArgsPools.Push(A_0);
            }
        }

        private void a(object A_0)
        {
            try
            {
                bool flag = true;
                while ((this._field_n && flag) && (!this._field_s && this.a()))
                {
                    SocketAsyncEventArgs e = SocketAsyncEventArgsPools.Pop();
                    e.Completed += new EventHandler<SocketAsyncEventArgs>(this.b);
                    try
                    {
                        flag = !this.Socket.AcceptAsync(e);
                        this._field_b = true;
                    }
                    catch (SocketException exception)
                    {
                        this.a((Exception) exception);
                        return;
                    }
                    catch (ObjectDisposedException exception2)
                    {
                        this.a((Exception) exception2);
                        return;
                    }
                    if (flag)
                    {
                        this.a(e);
                    }
                }
            }
            catch (Exception exception3)
            {
                this.a(exception3);
            }
        }

        private static void a(object A_0, SocketAsyncEventArgs A_1)
        {
            try
            {
                CreateChannelArgs args = new CreateChannelArgs {
                    Error = A_1.SocketError
                };
                if (A_1.SocketError == SocketError.Success)
                {
                    args.Channel = new TcpChannel(A_1.AcceptSocket);
                }
                Action<CreateChannelArgs> userToken = (Action<CreateChannelArgs>) A_1.UserToken;
                userToken(args);
            }
            catch
            {
            }
            finally
            {
                A_1.Completed -= new EventHandler<SocketAsyncEventArgs>(TcpServer.a);
                SocketAsyncEventArgsPools.Push(A_1);
            }
        }

        private Class_r b()
        {
            lock (this._field_j)
            {
                if (this._field_j.Count > 0)
                {
                    return this._field_j.Dequeue();
                }
                return null;
            }
        }

        private void b(TcpChannel A_0)
        {
            lock (this._field_c)
            {
                this.Clients.Remove(A_0);
            }
        }

        private void b(Class_r A_0)
        {
            lock (this._field_j)
            {
                this._field_j.Enqueue(A_0);
            }
        }

        private void b(object A_0)
        {
            while (this._field_n)
            {
                try
                {
                    this._field_d = this.b();
                    if (this._field_d != null)
                    {
                        this._field_f.Cancel = false;
                        this._field_f.Socket=(this._field_d._field_b);
                        this._field_f.Server=(this);
                        if (!this._field_i.a(new Action<Class_r>(this.a), this._field_d, this.c(), out this._field_e))
                        {
                            this.a(this._field_d._field_b);
                        }
                        this.OnChannelCreating(this._field_f);
                        if (!this._field_f.Cancel)
                        {
                            this.a(this._field_d);
                        }
                        else
                        {
                            this.a(this._field_d._field_b);
                        }
                    }
                    else
                    {
                        Thread.Sleep(10);
                    }
                    continue;
                }
                catch (Exception exception)
                {
                    this.a(exception);
                    continue;
                }
            }
        }

        private void b(object A_0, SocketAsyncEventArgs A_1)
        {
            object obj = null;
            this.a(A_1);
            this.a(obj);
        }

        internal int c()
        {
            return this.Clients.Count;
        }

        internal void c(TcpChannel A_0)
        {
            A_0._field_d = this._field_o.Count;
            A_0["_data"] = this._field_e;
        }

        public static TcpChannel CreateClient(IPEndPoint endpoint)
        {
            System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(endpoint);
            return new TcpChannel(socket);
        }

        public static TcpChannel CreateClient(IPAddress ip, int port)
        {
            return CreateClient(new IPEndPoint(ip, port));
        }

        public static TcpChannel CreateClient<T>(IPEndPoint endpoint, EventPacketRecievMessage receive) where T: Package
        {
            if (!TcpUtils._field_a)
            {
                throw NetTcpException.NotInitialize();
            }
            System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.Connect(endpoint);
            TcpChannel channel = new TcpChannel(socket);
            channel.SetPackage<T>().ReceiveMessage = receive;
            return channel;
        }

        public static TcpChannel CreateClient(string ip, int port)
        {
            return CreateClient(new IPEndPoint(IPAddress.Parse(ip), port));
        }

        public static TcpChannel CreateClient<T>(IPAddress ip, int port, EventPacketRecievMessage receive) where T: Package
        {
            return CreateClient<T>(new IPEndPoint(ip, port), receive);
        }

        public static TcpChannel CreateClient<T>(string ip, int port, EventPacketRecievMessage receive) where T: Package
        {
            return CreateClient<T>(new IPEndPoint(IPAddress.Parse(ip), port), receive);
        }

        public static void CreateClientAsync(IPEndPoint endpoint, Action<CreateChannelArgs> result)
        {
            if (!TcpUtils._field_a)
            {
                throw NetTcpException.NotInitialize();
            }
            SocketAsyncEventArgs e = SocketAsyncEventArgsPools.Pop();
            e.Completed += new EventHandler<SocketAsyncEventArgs>(TcpServer.a);
            try
            {
                e.UserToken = result;
                System.Net.Sockets.Socket socket = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                e.AcceptSocket = socket;
                e.RemoteEndPoint = endpoint;
                if (!socket.ConnectAsync(e))
                {
                    a(null, e);
                }
            }
            catch (Exception exception)
            {
                e.Completed -= new EventHandler<SocketAsyncEventArgs>(TcpServer.a);
                SocketAsyncEventArgsPools.Push(e);
                throw exception;
            }
        }

        public static void CreateClientAsync(IPAddress ip, int port, Action<CreateChannelArgs> result)
        {
            CreateClientAsync(new IPEndPoint(ip, port), result);
        }

        public static void CreateClientAsync(string ip, int port, Action<CreateChannelArgs> result)
        {
            CreateClientAsync(IPAddress.Parse(ip), port, result);
        }

        public void Dispose()
        {
            lock (this)
            {
                if (this._field_n)
                {
                    this.DetectHandler.Server=(null);
                    this._field_n = false;
                    foreach (TcpChannel channel in this.GetOnlines())
                    {
                        channel.CloseStatus = "Server Close!";
                        channel.Dispose();
                    }
                    this._field_o.Clear();
                    if (this.Socket != null)
                    {
                        ReleaseSocket(this.Socket);
                        this._field_h = null;
                    }
                    lock (this._field_j)
                    {
                        this._field_j.Clear();
                    }
                    this._field_f.Server=((TcpServer) null);
                    this._field_f = null;
                }
            }
        }

        public TcpChannel FindClient(long id, string name)
        {
            foreach (TcpChannel channel in this.GetOnlines())
            {
                if ((id == channel.ClientID) || (!string.IsNullOrEmpty(name) && (channel.Name == name)))
                {
                    return channel;
                }
            }
            return null;
        }

        public T GetFilter<T>() where T: IIPFiler, new()
        {
            lock (this._field_k)
            {
                Type key = typeof(T);
                if (!this._field_k.ContainsKey(key))
                {
                    this._field_k.Add(key, (default(T) == null) ? ((IIPFiler) Activator.CreateInstance<T>()) : ((IIPFiler) default(T)));
                }
                return (T) this._field_k[key];
            }
        }

        public TcpChannel[] GetOnlines()
        {
            TcpChannel[] channelArray2;
            lock (this._field_c)
            {
                try
                {
                    TcpChannel[] array = new TcpChannel[this.Clients.Count];
                    this.Clients.CopyTo(array, 0);
                    channelArray2 = array;
                }
                catch (Exception exception)
                {
                    this.a(exception);
                    channelArray2 = new TcpChannel[0];
                }
            }
            return channelArray2;
        }

        public void GetOnlines(ObjectArraySegment<TcpChannel> items)
        {
            lock (this._field_c)
            {
                try
                {
                    this.Clients.CopyTo(items.Array, 0);
                    items.Offset=(0);
                    items.Count=(this.Clients.Count);
                }
                catch (Exception exception)
                {
                    this.a(exception);
                }
            }
        }

        protected void OnChannelCreating(ChannelCreatingArgs e)
        {
            if (this._field_m != null)
            {
                this._field_m(this, this._field_f);
            }
            e.Cancel = this.c() >= this._field_e;
        }

        protected void OnClientDisposed(object source, ChannelDisposedEventArgs e)
        {
            try
            {
                e.Channel.Server=((TcpServer) null);
                this.b(e.Channel);
                if (this._field_r != null)
                {
                    this._field_r(this, e);
                }
            }
            catch (Exception exception)
            {
                this.a(exception);
            }
        }

        protected void OnConnected(TcpChannel e)
        {
            try
            {
                this.a(e);
                e.Server=(this);
                e.ChannelDisposed += new EventChannelDisposed(this.OnClientDisposed);
                if (this._field_q != null)
                {
                    ChannelDisposedEventArgs args = new ChannelDisposedEventArgs {
                        Channel = e,
                        Clean = true
                    };
                    this._field_q(this, args);
                }
            }
            catch (Exception exception)
            {
                string message = exception.Message;
                this.a(exception);
            }
        }

        protected virtual void OnError(TcpServerErrorArgs e)
        {
            if (this._field_a != null)
            {
                this._field_a(this, e);
            }
        }

        public void Open(int port)
        {
            this.Open(new IPEndPoint(IPAddress.Any, port));
        }

        public void Open(IPEndPoint ipendpoint)
        {
            this.Open(ipendpoint, 100);
        }

        public void Open(IPEndPoint ipendpoint, int listens)
        {
            if (!TcpUtils._field_a)
            {
                throw NetTcpException.NotInitialize();
            }
            this._field_p = ipendpoint;
            if (this._field_h != null)
            {
                this.Dispose();
            }
            this._field_h = new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.Socket.Bind(ipendpoint);
            this.Socket.Listen(listens);
            this._field_n = true;
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.b));
            ThreadPool.QueueUserWorkItem(new WaitCallback(this.a));
        }

        public void Open(string ip, int port)
        {
            this.Open(ip, port, 100);
        }

        public void Open(string ip, int port, int listens)
        {
            this.Open(new IPEndPoint(IPAddress.Parse(ip), port), listens);
        }

        public void Pause()
        {
            lock (this._field_c)
            {
                if (!this._field_s)
                {
                    this._field_s = true;
                }
            }
        }

        public static void ReleaseSocket(System.Net.Sockets.Socket socket)
        {
            if (socket != null)
            {
                lock (socket)
                {
                    try
                    {
                        if (socket != null)
                        {
                            socket.Shutdown(SocketShutdown.Both);
                        }
                    }
                    catch
                    {
                    }
                    try
                    {
                        if (socket != null)
                        {
                            socket.Close();
                        }
                    }
                    catch
                    {
                    }
                }
            }
        }

        public void Resume()
        {
            lock (this._field_c)
            {
                if (this._field_s)
                {
                    this._field_s = false;
                    if (!this._field_b)
                    {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(this.a));
                    }
                }
            }
        }

        public void SetFilter<T>() where T: IIPFiler, new()
        {
            lock (this._field_k)
            {
                this._field_k[typeof(T)] = (default(T) == null) ? ((IIPFiler) Activator.CreateInstance<T>()) : ((IIPFiler) default(T));
            }
        }

        public static void SetKeepAliveValues(System.Net.Sockets.Socket socket, uint first, uint interval)
        {
            byte[] array = new byte[Marshal.SizeOf(first) * 3];
            BitConverter.GetBytes((uint) 1).CopyTo(array, 0);
            BitConverter.GetBytes(first).CopyTo(array, Marshal.SizeOf(first));
            BitConverter.GetBytes(interval).CopyTo(array, (int) (Marshal.SizeOf(first) * 2));
            socket.IOControl(IOControlCode.KeepAliveValues, array, null);
        }

        public IList<TcpChannel> Clients
        {
            get
            {
                return this._field_o;
            }
        }

        public Encoding Coding
        {
            [CompilerGenerated]
            get
            {
                return this._field_u;
            }
            [CompilerGenerated]
            set
            {
                this._field_u = value;
            }
        }

        public DetectTimeoutHandler DetectHandler
        {
            get
            {
                return this._field_l;
            }
        }

        public bool EnabledChannelSendCompeletedEvent
        {
            [CompilerGenerated]
            get
            {
                return this._field_v;
            }
            [CompilerGenerated]
            set
            {
                this._field_v = value;
            }
        }

        public bool IsRunning
        {
            get
            {
                return this._field_n;
            }
        }

        public int QueueConnects
        {
            get
            {
                return this._field_j.Count;
            }
        }

        public System.Net.Sockets.Socket Socket
        {
            get
            {
                return this._field_h;
            }
        }
    }
}

